#include "client.h"

void setEcho(bool enable) {
	struct termios tty;
	tcgetattr(STDIN_FILENO, &tty);
	if (enable)
		tty.c_lflag |= ECHO;
	else
		tty.c_lflag &= ~ECHO;
	tcsetattr(STDIN_FILENO, TCSANOW, &tty);
}

char *getPassword(const char *prompt) {
	printf("%s", prompt);
	setEcho(false);  // 关闭回显
	char *password = (char *)malloc(100);
	fgets(password, 100, stdin);
	setEcho(true);   // 恢复回显
	printf("\n");     // 因为关闭回显时换行符不显示，手动补一个
	return password;
}

// 登陆验证
int loginCheck(char *username, const int sockfd, char *passwd) {

	// 创建TLV结构体
	tlvPacket_t tlv;

	// 用户验证
	while (1) {

		// 获取用户名
		printf("请输入用户名: ");
		fflush(stdout);
		fgets(username, sizeof(username), stdin);

		// 去除最后一个换行符
		if (username[strlen(username) -1] == '\n') {
			username[strlen(username) -1] = 0;
		}

		// 用户验证, TLV发送用户名
		tlv.type = LOGIN;
		tlv.length = strlen(username);
		memcpy(tlv.value, username, tlv.length);
		send(sockfd, &tlv, sizeof(tlv.type) + sizeof(tlv.length) +
		     tlv.length, MSG_NOSIGNAL);

		// 接收标志，判断用户是否已存在
		int userIsExist;
		int ret = recv(sockfd, &userIsExist, sizeof(int), MSG_WAITALL);
		if (ret == 0) {
			printf("服务端已退出！\n");
			exit(1);
		}

		// 用户不存在
		if (userIsExist == 0) {
			printf("用户不存在，是否创建新用户？是（y/Y），否（任意键）: ");
			char isCreate[4096] = {0};
			// 获取用户响应
			fgets(isCreate, sizeof(isCreate), stdin);

			// 去除最后一个换行符
			if (isCreate[strlen(isCreate) -1] == '\n') {
				isCreate[strlen(isCreate) -1] = 0;
			}

			// 创建新用户
			if (strcmp(isCreate, "y") == 0 || strcmp(isCreate, "Y") == 0) {
				// 发送TLV注册命令，和用户名
				tlv.type = REGISTER;
				send(sockfd, &tlv, sizeof(tlv.type) + sizeof(tlv.length) +
				     tlv.length, MSG_NOSIGNAL);

				// 接收盐值
				char plaintext[4096] = {0}; // 存储明文
				char ciphertext[4096] = {0}; // 存储密文
				char salt[4096] = {0};
				recv(sockfd, &tlv.type, sizeof(commandType_t), MSG_WAITALL);
				recv(sockfd, &tlv.length, sizeof(int), MSG_WAITALL);
				recv(sockfd, tlv.value, tlv.length, MSG_WAITALL);
				memcpy(salt, tlv.value, tlv.length);


				// 用户输入注册密码
				while (1) {
					char passwd1[4096] = {0};
					char passwd2[4096] = {0};
					char *tmp = getPassword("请输入密码：");
					memcpy(passwd1, tmp, strlen(tmp));
					free(tmp);
					tmp = getPassword("请再次输入密码：");
					memcpy(passwd2, tmp, strlen(tmp));
					free(tmp);
					if (strcmp(passwd1, passwd2) == 0) {
						// 密码一致，存储到明文
						memcpy(plaintext, passwd1, strlen(passwd1));
						break;
					}
					printf("两次密码不一致!\n");

				}

				// 生成并发送密文
				char *tmp = crypt(plaintext, salt);
				memcpy(ciphertext, tmp, strlen(tmp));
				tlv.type = REGISTER;
				tlv.length = strlen(ciphertext);
				
				memcpy(tlv.value, ciphertext, tlv.length);
				send(sockfd, &tlv, sizeof(tlv.type) + sizeof(tlv.length) +
				     tlv.length, MSG_NOSIGNAL);
				int registerTag;
				recv(sockfd, &registerTag, sizeof(int), MSG_WAITALL);

				if (registerTag == 1) {
					printf("注册成功！\n");
					// 传出明文密码
					memcpy(passwd, plaintext, strlen(plaintext));
					return 0; // 注册成功，跳过密码验证
				} else {
					printf("注册失败！\n");
					exit(-1);
				}
			}

			// 不创建新用户，继续输入用户名
			else {
				continue;
			}

		}

		// 用户存在
		else {
			break;
		}
	}

	// 密码验证
	// 接收盐值
	char plaintext[4096] = {0}; // 存储明文
	char ciphertext[4096] = {0}; // 存储密文
	char salt[4096] = {0};
	recv(sockfd, &tlv.type, sizeof(commandType_t), MSG_WAITALL);
	recv(sockfd, &tlv.length, sizeof(int), MSG_WAITALL);
	recv(sockfd, tlv.value, tlv.length, MSG_WAITALL);
	memcpy(salt, tlv.value, tlv.length);

	// 用户输入密码
	while (1) {

		// 获取密码明文
		char *tmp = getPassword("请输入密码：");
		memcpy(plaintext, tmp, strlen(tmp) +1);
		free(tmp);

		// 生成并发送密文
		tmp = crypt(plaintext, salt);
		memcpy(ciphertext, tmp, strlen(tmp) +1);
		memset(&tlv, 0, sizeof(tlv));
		tlv.type = LOGIN;
		tlv.length = strlen(ciphertext);
		memcpy(tlv.value, ciphertext, tlv.length);
		send(sockfd, &tlv, sizeof(tlv.type) + sizeof(tlv.length) +
		     tlv.length, MSG_NOSIGNAL);

		int loginTag;
		recv(sockfd, &loginTag, sizeof(int), MSG_WAITALL);
		if (loginTag == 1) {
			printf("登录成功！\n");

			// 传出明文密码
			memcpy(passwd, plaintext, strlen(plaintext));
			return 0;
		} else {
			printf("登录失败！\n");
		}
	}
}

